package com.h2cloud.JUCTest.reentrantReadWriteLock;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @Package: com.h2cloud.JUCTest.reentrantReadWriteLock
 * @ClassName: ReentrantReadWriteLock
 * @Author: h2cloud
 * @CreateTime: 2022/6/5 2:30 下午
 * @Description:
 */
public class reentrantReadWriteLockTest {

	public static void main(String[] args) throws InterruptedException {

		 DataContainer dataContainer = new DataContainer();
		 Thread t1 = new Thread(() -> {
		 	dataContainer.read();
		 	dataContainer.write();
		 }, "t1");
		 Thread t2 = new Thread(() -> {
		 	dataContainer.read();
		 	dataContainer.write();
		 }, "t2");
		 t1.start();
		 t2.start();

		ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
		ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
		ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();

		// 重入时  升级不支持：持有读锁的情况下，去获取写锁，会导致获取写锁永久等待
//		readLock.lock();
//		System.out.println("get readLock");
//		try {
//			writeLock.lock();
//			System.out.println("get writeLock");
//			try {
//
//			} finally {
//				writeLock.unlock();
//				System.out.println("unlock writeLock");
//			}
//		} finally {
//			readLock.unlock();
//			System.out.println("unlock readLock");
//		}

		// 重入时  降级支持：即持有写锁的情况下，可以获取读锁
//		writeLock.lock();
//		System.out.println("get writeLock");
//		try {
//			readLock.lock();
//			System.out.println("get readLock");
//			try {
//
//			} finally {
//				readLock.unlock();
//				System.out.println("unlock readLock");
//			}
//		} finally {
//			writeLock.unlock();
//			System.out.println("unlock writeLock");
//		}

	}

}

@Slf4j(topic = "c.DataContainer")
class DataContainer {

	private Object object = new Object();
	private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
	private ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
	private ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();

	public Object read() {
		readLock.lock();
		log.info("拿到读锁！");
		try {
			log.info("读取操作 ...");
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} finally {
			readLock.unlock();
			log.info("释放读锁！");
		}
		return object;
	}

	public void write() {
		writeLock.lock();
		log.info("拿到写锁！");
		try {
			log.info("写操作 ... ");
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} finally {
			writeLock.unlock();
			log.info("释放写锁！");
		}
	}

}
